import React from "react";
const boxStyle = {
    margin: '10px',
    border: '1px solid #ccc',
    borderRadius: "10px",
}
// react中可以通过props.children来实现 vue中的插槽
export function FancyBorder(props) {
    return (
        <div style={boxStyle} className={'FancyBorder FancyBorder-' + props.color}>
            <p>这是类似vue中的默认插槽</p>
            {props.children}
        </div>
    )
}

export function WelcomeDialog() {
    return (
        <FancyBorder color="blue">
            <p className="Dialog-title">
                Welcome
            </p>
            <p className="Dialog-message">
                Thank you for visiting our spacecraft!
            </p>
        </FancyBorder>
    );
}


// 通过props.chidren来实现具名插槽
// 组件内部同级节点或组件会依次放入props.children中
export function FancyBorder1(props) {
    console.log('FancyBorder1', props)
    return (
        <div style={boxStyle} className={'FancyBorder FancyBorder-' + props.color}>
            <p>通过children顺序实现具名插槽</p>
            {props.children[2]}
            {props.children[1]}
            {props.children[0]}
        </div>
    )
}

export function WelcomeDialog1() {
    // react 中直接在组件上使用 style级 className会失效 都会作为props传递
    return (
        <FancyBorder1 style={boxStyle} className={'FancyBorder FancyBorder-'} color="blue">
            <p className="Dialog-title">
                这是具名插槽内容0
            </p>
            <p className="Dialog-message">
                这是具名插槽内容1
            </p>
            <p className="Dialog-message">
                这是具名插槽内容2
            </p>
        </FancyBorder1>
    );
}

// 通过props传递jsx实现具名插槽 
// <headerDom /> 和 <footerDom /> 之类的 React 元素本质就是对象（object），所以你可以把它们当作 props，像其他数据一样传递。这种方法可能使你想起别的库中“槽”（slot）的概念
// 标签和组件 都会被react.createElement转换为object 
export function FancyBorder2(props) {
    console.log('FancyBorder1', props)
    return (
        <div style={boxStyle} className={'FancyBorder FancyBorder-' + props.color}>
            <p>通过props传递jsx实现具名插槽</p>
            {props.header}
            <p>+++++这是插槽分割线+++++</p>
            {props.content}
            {props.footer}
        </div>
    )
}
const headerDom = <p>这是传递给props.header的jsx</p>
const footerDom = <p>这是传递给props.footer的jsx</p>
function Content(props) {
    return (
        <p>这是传递给props.content的jsx组件</p>
    )
}
export function WelcomeDialog3() {
    return (
        <FancyBorder2 header={headerDom} footer={footerDom} content={<Content />}> </FancyBorder2>
    );
}

// 使用Render Props 实现作用域插槽
// 在jsx中表达式可以使用functionName(), 传递返回jsx组件函数的props,该函数可以接收父组件中的props和state, 子组件可以接收这些传递值
// 实现自组件使用父组件中数据
class Cat extends React.Component {
    constructor(props) {
        super(props)
        console.log('cat...', this.props)
    }
    componentDidUpdate() {
        console.log('componentDidUpdate---cat...')
    }
    render() {
        const { mouse } = this.props;
        return (
            <img src="https://www.legacy.reactjs.org" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
        );
    }
}
class Mouse extends React.Component {
    constructor(props) {
        super(props);
        this.handleMouseMove = this.handleMouseMove.bind(this);
        this.state = { x: 0, y: 0 };
    }

    handleMouseMove(event) {
        console.log('handleMouseMove..')
        this.setState({
            x: event.clientX,
            y: event.clientY
        });
    }

    render() {
        const slotsParams = {
            ...this.state,
            ...this.props
        }
        return (
            <div style={{ height: '100vh', border: '1px solid red', }} onMouseMove={this.handleMouseMove}>
                {/*
                    使用 `render`prop 动态决定要渲染的内容，
                    而不是给出一个 <Mouse> 渲染结果的静态表示
                */}
                {this.props.render(slotsParams)}
                <p>使用props.Render实现作用域插槽</p>
            </div>
        );
    }
}
export class MouseTracker extends React.Component {
    constructor(props) {
        super(props);
        this.state = { MouseTracker: 'MouseTracker中state' };
    }
     // 定义为实例方法，`this.renderTheCat`始终
    // 当我们在渲染中使用它时，它指的是相同的函数
    renderTheCat(mouse) {
        return <Cat {...this.props} mouse={mouse}  />;
    }
    render() {
        return (
            <div style={boxStyle} >
                <p>使用Render Props 实现作用域插槽</p>
                {/* 这种方式传递渲染函数,每个渲染的 `render` prop的值将会是不同的。 会引起组件不必要更新,因而在同时也抵消了继承自 React.PureComponent 的 <Mouse> 组件的效果！  */}
                {/* <Mouse mouseProps1={this.state.MouseTracker} render={mouse => (
                    <Cat {...this.props} mouse={mouse} />
                )} /> */}
                <Mouse mouseProps1={this.state.MouseTracker} render={this.renderTheCat} />

            </div>
        );
    }
}



// 如果你出于某种原因真的想要 HOC，那么你可以轻松实现
// 使用具有 render prop 的普通组件创建一个！
function withMouse(Component) {
    return class extends React.Component {
        render() {
            return (
                <Mouse render={mouse => (
                    <Component {...this.props} mouse={mouse} />
                )} />
            );
        }
    }
}



// 在class 中使用插槽
function Dialog(props) {
    return (
        <FancyBorder color="blue">
            <p className="Dialog-title">
                {props.title}
            </p>
            <p className="Dialog-message">
                {props.message}
            </p>
            {props.children}
        </FancyBorder>
    );
}

export class SignUpDialog extends React.Component {
    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.handleSignUp = this.handleSignUp.bind(this);
        this.state = { login: '' };
    }

    render() {
        return (
            <Dialog title="在class组件中使用插槽"
                message="How should we refer to you?">
                <input value={this.state.login}
                    onChange={this.handleChange} />
                <button onClick={this.handleSignUp}>
                    Sign Me Up!
                </button>
            </Dialog>
        );
    }

    handleChange(e) {
        this.setState({ login: e.target.value });
    }

    handleSignUp() {
        alert(`Welcome aboard, ${this.state.login}!`);
    }
}

// 在 Facebook，我们在成百上千个组件中使用 React。我们并没有发现需要使用继承来构建组件层次的情况。
// Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意：组件可以接受任意 props，包括基本数据类型，React 元素以及函数。

